﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Sinacor.Infra.Core.ProcessManager.Server;
using Sinacor.Infra.Service.Validation;
using Sinacor.Infra.Common.Exceptions;
using Sinacor.Infra.Service.ExceptionHandling;
using PSE.Framework.Communication.Client.File.FlatFile;
using PSE.Framework.Communication.Configuration.File.FlatFile;
using PSE.Framework.Communication.Configuration;
using System.IO;
using PSE.Framework.Communication.Adapters.File;
using PSE.ProcessManager.Common.Process;
using Sinacor.Infra.Service.Common;

namespace Sinacor.Process.Bovespa.Distribuicao.Server.ProcessLogic
{
    public class Exportacao : BaseProcessLogic
    {
        #region Atributos

        private int _erroDataPregaoInvalida = 109762;
        private int _erroClienteNaoCadastrado = 109834;
        private int _erroExportacaoSemRegistros = 109840;
        private int _erroCorrespondenteSemMovimento = 109859;
        private int _erroDivergenciaPraca = 109860;

        #endregion

        #region Propriedades

        public int ErroClienteNaoCadastrado
        {
            get { return _erroClienteNaoCadastrado; }
            set { _erroClienteNaoCadastrado = value; }
        }

        public int ErroDataPregaoInvalida
        {
            get { return _erroDataPregaoInvalida; }
            set { _erroDataPregaoInvalida = value; }
        }

        public int ErroExportacaoSemRegistros
        {
            get { return _erroExportacaoSemRegistros; }
            set { _erroExportacaoSemRegistros = value; }
        }

        public int ErroCorrespondenteSemMovimento
        {
            get { return _erroCorrespondenteSemMovimento; }
            set { _erroCorrespondenteSemMovimento = value; }
        }

        public int ErroDivergenciaPraca
        {
            get { return _erroDivergenciaPraca; }
            set { _erroDivergenciaPraca = value; }
        }

        #endregion

        #region Construtor

        /// <summary>
        /// Construtor padrão
        /// </summary>
        public Exportacao()
        {
        }

        #endregion

        #region Eventos
        public event EventHandler<ProcessEventArgs<ProcessEntity.ResultadoExportacao>> ExportacaoConcluida;
        #endregion

        #region Métodos Públicos

        public void ExportarDistribuicao(ProcessEntity.Parameter.FiltroExportacaoDistribuicao entity)
        {
            Communication.ControleMovimentoOrdens communicatonControleMovimentoOrdens = null;
            ProcessEntity.InformacoesMovimento informacaoMovimento = null;
            Communication.CalendarioBolsa communicationCalendarioBolsa;
            Communication.CalendarioOrdens communicationCalendarioOrdens;
            List<ProcessEntity.Calendario> calendario = null;
            Layout.DistribuicaoHeader header = null;
            List<ProcessEntity.DistribuicaoDetail> listaExportacao = null;
            Layout.DistribuicaoDetail distribuicaoDetail = null;
            decimal porcentagemPorRegistro = 0;
            int registroAtual = 0;
            int codigoEmpresaBolsa = 0;
            ResourceAccess.ImportacaoExportacao raImportacaoExportacao;
            ResourceAccess.Exportacao raExportacao;
            Translator.ProcessEntityToLayout.Distribuicao toLayoutDistribuicao;
            string nomePraca = string.Empty;
            string resourceKeyOut;
            bool ocorreuErro = false;

            communicatonControleMovimentoOrdens = new Communication.ControleMovimentoOrdens();
            communicationCalendarioBolsa = new Communication.CalendarioBolsa();
            communicationCalendarioOrdens = new Communication.CalendarioOrdens();
            raImportacaoExportacao = new ResourceAccess.ImportacaoExportacao();
            raExportacao = new ResourceAccess.Exportacao();
            toLayoutDistribuicao = new Translator.ProcessEntityToLayout.Distribuicao();

            //Valida RuleSet
            SinacorValidation validation = new SinacorValidation();
            validation.Validate<ProcessEntity.Parameter.FiltroExportacaoDistribuicao>(entity);

            //Validar correspondente
            if (!raExportacao.VerificarCorrespondente(entity)
                && !IsAborted)
                throw new BusinessException(this.ErroCorrespondenteSemMovimento);

            //Verifica se tipo de sistema igual a "Bolsa"
            if (entity.TipoSistema == ProcessEntity.Enum.TipoSistema.Bolsa)
            {
                //Consulta calendario Bolsa
                calendario = communicationCalendarioBolsa.ConsultarCalendarios(
                    new ProcessEntity.Parameter.FiltroCalendario
                    {
                        DataPregao = entity.DataPregao.Value
                    });
            }
            else
            {
                //Consulta calendario Ordens
                calendario = communicationCalendarioOrdens.ConsultarCalendarios(
                    new ProcessEntity.Parameter.FiltroCalendario
                    {
                        DataPregao = entity.DataPregao.Value
                    });
            }

            //Verifica se data pregao é válida
            if (calendario == null
                && !IsAborted)
                throw new BusinessException(this.ErroDataPregaoInvalida);

            //Consultar exportacao
            listaExportacao = raExportacao.ConsultarDistribuicaoExportar(entity);

            if (listaExportacao.Count != 0)
                porcentagemPorRegistro = 100M / (decimal)listaExportacao.Count;
            else if(!IsAborted)
                throw new BusinessException(this.ErroExportacaoSemRegistros);

            if (!IsAborted)
            {
                //Consulta codigo empresa bolsa
                codigoEmpresaBolsa = raImportacaoExportacao.ObterCodigoEmpresaBolsa();
            }

            if(!IsAborted)
            {
                //Obtem informações do movimento
                informacaoMovimento = communicatonControleMovimentoOrdens.ObterInformacoesMovimento();
            }

            if(!IsAborted)
            {
                using (FlatFileOutputClient client = new FlatFileOutputClient())
                {
                    try
                    {
                        //Abri arquivo
                        client.Open("ExportacaoTORDIST");

                        FlatFileOutputConfiguration _config = CommunicationConfigurationManager.GetInstance().GetCommunicationClientConfiguration("ExportacaoTORDIST") as FlatFileOutputConfiguration;

                        FileInfo fi = new FileInfo(entity.NomeArquivo);
                        client.OpenFile(new FileOpenParameter(_config == null ? null : _config.OutputPath,
                                                              fi.Name));

                        //Monta header
                        header = new Layout.DistribuicaoHeader
                        {
                            CodigoUsuario = codigoEmpresaBolsa,
                            DataPregao = entity.DataPregao.Value,
                            NomeArquivo = "TORDIST",
                            TipoDistribuicao = Layout.Enum.TipoDistribuicao.D,
                            TipoRegistro = "H",
                            Reserva = string.Empty
                        };

                        //Escreve header no arquivo
                        client.WriteRecord(header, "DistribuicaoHeader");

                        //Exclui registros
                        raExportacao.ExcluirErrosExportacao();

                        foreach (ProcessEntity.DistribuicaoDetail item in listaExportacao)
                        {
                            if (IsAborted)
                                break;

                            if (item.CodigoClienteOutraBolsa == -1)
                            {
                                ocorreuErro = true;

                                //Inserção na tabela de erros
                                if (item.BolsaNegocio == ProcessEntity.Enum.BolsaNegocio.Bovespa ||
                                    item.BolsaNegocio == ProcessEntity.Enum.BolsaNegocio.Soma ||
                                    item.BolsaNegocio == ProcessEntity.Enum.BolsaNegocio.MAIS ||
                                    item.BolsaNegocio == ProcessEntity.Enum.BolsaNegocio.SOMAFIX ||
                                    item.BolsaNegocio == ProcessEntity.Enum.BolsaNegocio.BOVESPAFIX)
                                {
                                    nomePraca = "SP";
                                }
                                else if (item.BolsaNegocio == ProcessEntity.Enum.BolsaNegocio.BOVERJ)
                                {
                                    nomePraca = "RJ";
                                }
                                else if (item.BolsaNegocio == ProcessEntity.Enum.BolsaNegocio.BOVMESB)
                                {
                                    nomePraca = "BH";
                                }


                                raExportacao.InserirErroDistribuicao(new ProcessEntity.Parameter.FiltroErro
                                {
                                    CodigoBolsa = EnumConverter.ToString<ProcessEntity.Enum.BolsaNegocio>(item.BolsaNegocio),
                                    CodigoCliente = item.CodigoCliente,
                                    Praca = nomePraca,
                                    DataMovimento = informacaoMovimento.DataMovimento,
                                    DataPregao = entity.DataPregao.Value,
                                    DescricaoErro = string.Format(ErrorMessage.RetrieveErrorMessage(this.ErroDivergenciaPraca, out resourceKeyOut), entity.CodigoCorrespondente, nomePraca)
                                });
                            }
                            else
                            {
                                //Tradução para Layout
                                distribuicaoDetail = toLayoutDistribuicao.ToDistribuicaoDetail(item);

                                //Escreve registro
                                if (distribuicaoDetail != null)
                                    client.WriteRecord(distribuicaoDetail, "DistribuicaoDetail");
                            }

                            registroAtual++;

                            //Atualiza status
                            SendStatus(Convert.ToInt32(Math.Floor(porcentagemPorRegistro * registroAtual)), "Bovespa.ImportacaoExportacao.Message.ExportandoArquivo");
                        }

                        //Fechar arquivo
                        client.CloseFile();
                    }
                    catch
                    {
                        if (client.Status == PSE.Framework.Communication.CommunicationStatus.Opened)
                            client.CancelFile();

                        throw;
                    }
                }
            }

            //Conclui exportação
            if (ExportacaoConcluida != null
                && !IsAborted)
                ExportacaoConcluida(this, new ProcessEventArgs<Sinacor.Process.Bovespa.Distribuicao.ProcessEntity.ResultadoExportacao>(new ProcessEntity.ResultadoExportacao { Sucesso = !ocorreuErro }));
        }

        #endregion

        #region Métodos Privados

        private void AtualizaStatus(int progress, string resourceKey)
        {
            this.Status.Progress = progress;
            this.Status.Step = resourceKey;
            this.SendStatus();
        }

        #endregion
    }
}
